#include "cabrillo_config.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <glib.h>
#include <gtk/gtk.h>
#include "../ui/ui_manager.h"
#include "../app/main_app.h"

// Static member initialization
CabrilloConfig* CabrilloConfig::instance = nullptr;

// Private constructor
CabrilloConfig::CabrilloConfig() {
    // Initialize with default values if needed
}

// Singleton instance access
CabrilloConfig* CabrilloConfig::getInstance() {
    if (instance == nullptr) {
        instance = new CabrilloConfig();
    }
    return instance;
}

// Helper function to trim whitespace from both ends of a string
static std::string trim_cabrillo(const std::string& str) {
    const std::string whitespace = " \t\r\n";
    size_t start = str.find_first_not_of(whitespace);
    if (start == std::string::npos) {
        return "";
    }
    size_t end = str.find_last_not_of(whitespace);
    return str.substr(start, end - start + 1);
}

// Function to load configuration from file
bool CabrilloConfig::loadConfig(const std::string& configFile) {
    std::string configPath;
    
    // Clear existing configuration
    configMap.clear();
    
    // Load config file directly from the config directory relative to the executable
    char* execPath = g_file_read_link("/proc/self/exe", NULL);
    char* configFilePath = nullptr;
    
    if (execPath) {
        char* execDir = g_path_get_dirname(execPath);
        // If configFile already contains "config/" prefix, don't add it again
        if (configFile.find("config/") == 0) {
            configFilePath = g_build_filename(execDir, configFile.c_str(), NULL);
        } else {
            configFilePath = g_build_filename(execDir, "config", configFile.c_str(), NULL);
        }
        g_free(execDir);
        g_free(execPath);
    }
    
    bool configFound = false;
    if (configFilePath) {
        std::ifstream file(configFilePath);
        if (file.is_open()) {
            configPath = configFilePath;
            configFound = true;
            std::cout << "找到Cabrillo配置文件: " << configPath << std::endl;
            file.close();
        } else {
            std::cerr << "无法打开Cabrillo配置文件: " << configFilePath << std::endl;
        }
        g_free(configFilePath);
    }
    
    if (!configFound) {
        std::cerr << "无法找到Cabrillo配置文件: " << configFile << std::endl;
        return false;
    }
    
    // Parse the configuration file
    std::ifstream file(configPath);
    if (!file.is_open()) {
        std::cerr << "无法打开配置文件: " << configPath << std::endl;
        return false;
    }
    
    std::string line;
    std::string currentSection;
    
    while (std::getline(file, line)) {
        // Remove leading/trailing whitespace
        line = trim_cabrillo(line);
        
        // Skip empty lines and comments
        if (line.empty() || line[0] == '#' || line[0] == ';') {
            continue;
        }
        
        // Check for section header
        if (line[0] == '[' && line[line.size() - 1] == ']') {
            currentSection = line.substr(1, line.size() - 2);
            continue;
        }
        
        // Parse key=value pairs
        size_t equalPos = line.find('=');
        if (equalPos != std::string::npos) {
            std::string key = trim_cabrillo(line.substr(0, equalPos));
            std::string value = trim_cabrillo(line.substr(equalPos + 1));
            
            // If we're in a section, prefix the key with the section name
            if (!currentSection.empty()) {
                key = currentSection + "." + key;
            }
            
            configMap[key] = value;
        }
    }
    
    file.close();
    std::cout << "成功加载Cabrillo配置文件: " << configPath << std::endl;
    return true;
}

// Get configuration value by key
std::string CabrilloConfig::get(const std::string& key) const {
    auto it = configMap.find(key);
    if (it != configMap.end()) {
        return it->second;
    }
    return "";
}

// Get configuration value by key with default value
std::string CabrilloConfig::get(const std::string& key, const std::string& defaultValue) const {
    auto it = configMap.find(key);
    if (it != configMap.end()) {
        return it->second;
    }
    return defaultValue;
}

// Check if a key exists in configuration
bool CabrilloConfig::hasKey(const std::string& key) const {
    return configMap.find(key) != configMap.end();
}

// Get all configuration as map
const std::map<std::string, std::string>& CabrilloConfig::getAllConfig() const {
    return configMap;
}

// Save configuration to file
bool CabrilloConfig::saveConfig(const std::string& configFile) {
    std::string configPath;
    
    // Determine the config file path
    char* execPath = g_file_read_link("/proc/self/exe", NULL);
    char* configFilePath = nullptr;
    
    if (execPath) {
        char* execDir = g_path_get_dirname(execPath);
        // If configFile already contains "config/" prefix, don't add it again
        if (configFile.find("config/") == 0) {
            configFilePath = g_build_filename(execDir, configFile.c_str(), NULL);
        } else {
            configFilePath = g_build_filename(execDir, "config", configFile.c_str(), NULL);
        }
        g_free(execDir);
        g_free(execPath);
    }
    
    if (!configFilePath) {
        std::cerr << "无法确定配置文件路径" << std::endl;
        return false;
    }
    
    configPath = configFilePath;
    g_free(configFilePath);
    
    // Create directory if it doesn't exist
    char* configDir = g_path_get_dirname(configPath.c_str());
    if (configDir) {
        if (g_mkdir_with_parents(configDir, 0755) != 0) {
            std::cerr << "无法创建配置目录: " << configDir << std::endl;
            g_free(configDir);
            return false;
        }
        g_free(configDir);
    }
    
    // Write configuration to file
    std::ofstream file(configPath);
    if (!file.is_open()) {
        std::cerr << "无法打开配置文件进行写入: " << configPath << std::endl;
        return false;
    }
    
    // Group configuration by sections
    std::map<std::string, std::map<std::string, std::string>> sections;
    
    for (const auto& pair : configMap) {
        std::string key = pair.first;
        std::string value = pair.second;
        
        // Split key into section and actual key
        size_t dotPos = key.find('.');
        if (dotPos != std::string::npos) {
            std::string section = key.substr(0, dotPos);
            std::string actualKey = key.substr(dotPos + 1);
            sections[section][actualKey] = value;
        } else {
            // Keys without section go to a default section
            sections[""][key] = value;
        }
    }
    std::string currentQsoType = "DX";
    // Write sections to file
    for (const auto& sectionPair : sections) {
        const std::string& sectionName = sectionPair.first;
        const std::map<std::string, std::string>& sectionData = sectionPair.second;
        
        // Write section header if it's not the default section
        if (!sectionName.empty()) {
            file << "[" << sectionName << "]\n";
        }
        
        // Write key-value pairs
        for (const auto& dataPair : sectionData) {
            if(dataPair.first == "CONTEST"){
                currentQsoType = dataPair.second;
            }
            file << dataPair.first << " = " << dataPair.second << "\n";
        }
        
        // Add empty line between sections
        file << "\n";
    }
    
    file.close();
    std::cout << "成功保存Cabrillo配置文件: " << configPath << std::endl;
    //取得配置中的 CabrilloConfig.CONTEST 项
    // 直接调用MainApp::load_config_to_buttons函数加载配置到按钮
    GtkBuilder* builder = UIManager::get_builder();
    if (builder) {
        GtkWidget* main_window = UIManager::get_main_window(builder);
        if (main_window) {
            CabrilloConfig* cabrilloConfig = CabrilloConfig::getInstance();
            cabrilloConfig->loadConfig(configPath);
            MainApp::load_config_to_buttons(main_window, currentQsoType, builder);
        }
    }

    return true;
}

// Set configuration value
void CabrilloConfig::set(const std::string& key, const std::string& value) {
    configMap[key] = value;
}